home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v16n09 / bob12.exe / BOBSCN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-18  |  8.0 KB  |  407 lines

  1. /* bobscn.c - a lexical scanner */
  2. /*
  3.     Copyright (c) 1991, by David Michael Betz
  4.     All rights reserved
  5. */
  6.  
  7. #include <setjmp.h>
  8. #include "bob.h"
  9.  
  10. /* useful definitions */
  11. #define LSIZE    200
  12.  
  13. /* keyword table */
  14. static struct { char *kt_keyword; int kt_token; } ktab[] = {
  15. { "class",    T_CLASS        },
  16. { "static",    T_STATIC    },
  17. { "if",        T_IF        },
  18. { "else",    T_ELSE        },
  19. { "while",    T_WHILE        },
  20. { "return",    T_RETURN    },
  21. { "for",    T_FOR        },
  22. { "break",    T_BREAK        },
  23. { "continue",     T_CONTINUE    },
  24. { "do",        T_DO        },
  25. { "new",    T_NEW        },
  26. { "nil",    T_NIL        },
  27. { NULL,        0        }};
  28.  
  29. /* token name table */
  30. static char *t_names[] = {
  31. "<string>",
  32. "<identifier>",
  33. "<number>",
  34. "class",
  35. "static",
  36. "if",
  37. "else",
  38. "while",
  39. "return",
  40. "for",
  41. "break",
  42. "continue",
  43. "do",
  44. "new",
  45. "nil",
  46. "<=",
  47. "==",
  48. "!=",
  49. ">=",
  50. "<<",
  51. ">>",
  52. "&&",
  53. "||",
  54. "++",
  55. "--",
  56. "+=",
  57. "-=",
  58. "*=",
  59. "/=",
  60. "%=",
  61. "&=",
  62. "|=",
  63. "^=",
  64. "<<=",
  65. ">>=",
  66. "::",
  67. "->"};
  68.  
  69. /* global variables */
  70. int t_value;        /* numeric value */
  71. char t_token[TKNSIZE+1];/* token string */
  72.  
  73. /* local variables */
  74. static int (*getcf)();    /* getc function */
  75. static void *getcd;    /* getc data */
  76. static int savetkn;    /* look ahead token */
  77. static int savech;    /* look ahead character */
  78. static int lastch;    /* last input character */
  79. static char line[LSIZE];/* last input line */
  80. static char *lptr;    /* line pointer */
  81. static int lnum;    /* line number */
  82.  
  83. /* init_scanner - initialize the scanner */
  84. init_scanner(gf,gd)
  85.   int (*gf)(); void *gd;
  86. {
  87.     /* remember the getc function and data */
  88.     getcf = gf; getcd = gd;
  89.  
  90.     /* setup the line buffer */
  91.     lptr = line; *lptr = '\0';
  92.     lnum = 0;
  93.  
  94.     /* no lookahead yet */
  95.     savetkn = T_NOTOKEN;
  96.     savech = '\0';
  97.  
  98.     /* no last character */
  99.     lastch = '\0';
  100. }
  101.  
  102. /* token - get the next token */
  103. int token()
  104. {
  105.     int tkn;
  106.  
  107.     if ((tkn = savetkn) != T_NOTOKEN)
  108.     savetkn = T_NOTOKEN;
  109.     else
  110.     tkn = rtoken();
  111.     return (tkn);
  112. }
  113.  
  114. /* stoken - save a token */
  115. stoken(tkn)
  116.   int tkn;
  117. {
  118.     savetkn = tkn;
  119. }
  120.  
  121. /* tkn_name - get the name of a token */
  122. char *tkn_name(tkn)
  123.   int tkn;
  124. {
  125.     static char tname[2];
  126.     if (tkn == T_EOF)
  127.     return ("<eof>");
  128.     else if (tkn >= _TMIN && tkn <= _TMAX)
  129.     return (t_names[tkn-_TMIN]);
  130.     tname[0] = tkn;
  131.     tname[1] = '\0';
  132.     return (tname);
  133. }
  134.  
  135. /* rtoken - read the next token */
  136. static int rtoken()
  137. {
  138.     int ch,ch2;
  139.  
  140.     /* check the next character */
  141.     for (;;)
  142.     switch (ch = skipspaces()) {
  143.     case EOF:    return (T_EOF);
  144.     case '"':    return (getstring());
  145.     case '\'':    return (getcharacter());
  146.     case '<':    switch (ch = getch()) {
  147.             case '=':
  148.                 return (T_LE);
  149.             case '<':
  150.                 if ((ch = getch()) == '=')
  151.                 return (T_SHLEQ);
  152.                 savech = ch;
  153.                 return (T_SHL);
  154.             default:
  155.                 savech = ch;
  156.                 return ('<');
  157.             }
  158.     case '=':    if ((ch = getch()) == '=')
  159.                 return (T_EQ);
  160.             savech = ch;
  161.             return ('=');
  162.     case '!':    if ((ch = getch()) == '=')
  163.                 return (T_NE);
  164.             savech = ch;
  165.             return ('!');
  166.     case '>':    switch (ch = getch()) {
  167.             case '=':
  168.                 return (T_GE);
  169.             case '>':
  170.                 if ((ch = getch()) == '=')
  171.                 return (T_SHREQ);
  172.                 savech = ch;
  173.                 return (T_SHR);
  174.             default:
  175.                 savech = ch;
  176.                 return ('>');
  177.             }
  178.     case '&':    switch (ch = getch()) {
  179.             case '&':
  180.                 return (T_AND);
  181.             case '=':
  182.                 return (T_ANDEQ);
  183.             default:
  184.                 savech = ch;
  185.                 return ('&');
  186.             }
  187.     case '|':    switch (ch = getch()) {
  188.             case '|':
  189.                 return (T_AND);
  190.             case '=':
  191.                 return (T_OREQ);
  192.             default:
  193.                 savech = ch;
  194.                 return ('|');
  195.             }
  196.     case '^':    if ((ch = getch()) == '=')
  197.                 return (T_XOREQ);
  198.             savech = ch;
  199.             return ('^');
  200.     case '+':    switch (ch = getch()) {
  201.             case '+':
  202.                 return (T_INC);
  203.             case '=':
  204.                 return (T_ADDEQ);
  205.             default:
  206.                 savech = ch;
  207.                 return ('+');
  208.             }
  209.     case '-':    switch (ch = getch()) {
  210.             case '-':
  211.                 return (T_DEC);
  212.             case '=':
  213.                 return (T_SUBEQ);
  214.             case '>':
  215.                 return (T_MEMREF);
  216.             default:
  217.                 savech = ch;
  218.                 return ('-');
  219.             }
  220.     case '*':    if ((ch = getch()) == '=')
  221.                 return (T_MULEQ);
  222.             savech = ch;
  223.             return ('*');
  224.     case '/':    switch (ch = getch()) {
  225.             case '=':
  226.                 return (T_DIVEQ);
  227.             case '/':
  228.                 while ((ch = getch()) != EOF)
  229.                 if (ch == '\n')
  230.                     break;
  231.                 break;
  232.             case '*':
  233.                 ch = ch2 = EOF;
  234.                 for (; (ch2 = getch()) != EOF; ch = ch2)
  235.                 if (ch == '*' && ch2 == '/')
  236.                     break;
  237.                 break;
  238.             default:
  239.                 savech = ch;
  240.                 return ('/');
  241.             }
  242.             break;
  243.     case ':':    if ((ch = getch()) == ':')
  244.                 return (T_CC);
  245.             savech = ch;
  246.             return (':');
  247.     default:    if (isdigit(ch))
  248.                 return (getnumber(ch));
  249.             else if (isidchar(ch))
  250.                 return (getid(ch));
  251.             else {
  252.                 t_token[0] = ch;
  253.                 t_token[1] = '\0';
  254.                 return (ch);
  255.             }
  256.     }
  257. }
  258.  
  259. /* getstring - get a string */
  260. static int getstring()
  261. {
  262.     char *p;
  263.     int ch;
  264.  
  265.     /* get the string */
  266.     p = t_token;
  267.     while ((ch = literalch()) != EOF && ch != '"')
  268.     *p++ = ch;
  269.     if (ch == EOF)
  270.     savech = EOF;
  271.     *p = '\0';
  272.     return (T_STRING);
  273. }
  274.  
  275. /* getcharacter - get a character constant */
  276. static int getcharacter()
  277. {
  278.     t_value = literalch();
  279.     t_token[0] = t_value;
  280.     t_token[1] = '\0';
  281.     if (getch() != '\'')
  282.     parse_error("Expecting a closing single quote");
  283.     return (T_NUMBER);
  284. }
  285.  
  286. /* literalch - get a character from a literal string */
  287. static int literalch()
  288. {
  289.     int ch;
  290.     if ((ch = getch()) == '\\')
  291.     switch (ch = getch()) {
  292.     case 'n':  ch = '\n'; break;
  293.     case 't':  ch = '\t'; break;
  294.     case EOF:  ch = '\\'; savech = EOF; break;
  295.     }
  296.     return (ch);
  297. }
  298.  
  299. /* getid - get an identifier */
  300. static int getid(ch)
  301.   int ch;
  302. {
  303.     char *p;
  304.     int i;
  305.  
  306.     /* get the identifier */
  307.     p = t_token; *p++ = ch;
  308.     while ((ch = getch()) != EOF && isidchar(ch))
  309.     *p++ = ch;
  310.     savech = ch;
  311.     *p = '\0';
  312.  
  313.     /* check to see if it is a keyword */
  314.     for (i = 0; ktab[i].kt_keyword != NULL; ++i)
  315.     if (strcmp(ktab[i].kt_keyword,t_token) == 0)
  316.         return (ktab[i].kt_token);
  317.     return (T_IDENTIFIER);
  318. }
  319.  
  320. /* getnumber - get a number */
  321. static int getnumber(ch)
  322.   int ch;
  323. {
  324.     char *p;
  325.  
  326.     /* get the number */
  327.     p = t_token; *p++ = ch; t_value = ch - '0';
  328.     while ((ch = getch()) != EOF && isdigit(ch)) {
  329.     t_value = t_value * 10 + ch - '0';
  330.     *p++ = ch;
  331.     }
  332.     savech = ch;
  333.     *p = '\0';
  334.     return (T_NUMBER);
  335. }
  336.  
  337. /* skipspaces - skip leading spaces */
  338. static skipspaces()
  339. {
  340.     int ch;
  341.     while ((ch = getch()) != '\0' && isspace(ch))
  342.     ;
  343.     return (ch);
  344. }
  345.  
  346. /* isidchar - is this an identifier character */
  347. static int isidchar(ch)
  348.   int ch;
  349. {
  350.     return (isupper(ch)
  351.          || islower(ch)
  352.          || isdigit(ch)
  353.          || ch == '_');
  354. }
  355.  
  356. /* getch - get the next character */
  357. static int getch()
  358. {
  359.     int ch;
  360.     
  361.     /* check for a lookahead character */
  362.     if ((ch = savech) != '\0')
  363.     savech = '\0';
  364.  
  365.     /* check for a buffered character */
  366.     else {
  367.     while ((ch = *lptr++) == '\0') {
  368.  
  369.         /* check for being at the end of file */
  370.         if (lastch == EOF)
  371.         return (EOF);
  372.  
  373.         /* read the next line */
  374.         lptr = line;
  375.         while ((lastch = (*getcf)(getcd)) != EOF && lastch != '\n')
  376.         *lptr++ = lastch;
  377.         *lptr++ = '\n'; *lptr = '\0';
  378.         lptr = line;
  379.         ++lnum;
  380.     }
  381.     }
  382.  
  383.     /* return the current character */
  384.     return (ch);
  385. }
  386.  
  387. /* parse_error - report an error in the current line */
  388. parse_error(msg)
  389.   char *msg;
  390. {
  391.     extern jmp_buf error_trap;
  392.     char buf[LSIZE],*src,*dst;
  393.  
  394.     /* redisplay the line with the error */
  395.     sprintf(buf,">>> %s <<<\n>>> in line %d <<<\n%s",msg,lnum,line);
  396.     osputs(buf);
  397.  
  398.     /* point to the position immediately following the error */
  399.     for (src = line, dst = buf; src < lptr-1; ++src)
  400.     *dst++ = (*src == '\t' ? '\t' : ' ');
  401.     *dst++ = '^'; *dst++ = '\n'; *dst = '\0';
  402.     osputs(buf);
  403.  
  404.     /* invoke the error trap */
  405.     longjmp(error_trap,1);
  406. }
  407.